package laba5;

import interfaces.task5.ArrayCollection;
import interfaces.task5.ArrayIterator;
import static java.lang.System.arraycopy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * 
 * @author yakimovich
 */
@SuppressWarnings("rawtypes")
public class ArrayCollectionImpl<E extends Object> implements ArrayCollection {

	/**
	 * The array to store the items in a collection.
	 */
	private Object[] data;

	/**
	 * Size of the collection.
	 */
	private int size;

	/**
	 * Create ArrayCollectionImpl with initial capacity.
	 * @param initialCapacity
	 */
	public ArrayCollectionImpl(int initialCapacity) {
		if (initialCapacity < 0) {
			throw new IllegalArgumentException("Illegal Capacity: "
					+ initialCapacity);
		}
		this.data = new Object[initialCapacity];
		size = 0;
	}

	/**
	 * Create initialCapacity by default.
	 */
	public ArrayCollectionImpl() {
		this(0);
	}

	/**
	 * @return data array of ArrayCollectionImpl.
	 */
	@Override
	public Object[] getArray() {
		return data;
	}

	/**
	 * Set data array for ArrayCollectionImpl.
	 * @param es
	 *            - array for set
	 */
	@Override
	public void setArray(Object[] es) {
		this.data = es;
		size = 0;
		for (int i = data.length - 1; i >= 0; i--) {
			if (data[i] != null) {
				size = i + 1;
				return;
			}
		}
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public boolean contains(Object o) {
		int index = -1;
		if (o == null) {
			for (int i = 0; i < size; i++) {
				if (data[i] == null) {
					index = i;
				}
			}
		} else {
			for (int i = 0; i < size; i++) {
				if (o.equals(data[i])) {
					index = i;
				}
			}
		}
		return index >= 0;
	}

	@Override
	public Iterator iterator() {
		return new ArrayIteratorImpl();
	}

	/**
	 * Create ArrayCollectionImpl with initial capacity.
	 * @param initialCapacity
	 */
	protected class ArrayIteratorImpl implements ArrayIterator {

		protected int cursor;

		// index of last element returned; -1 if no such
		int lastRet = -1;

		/**
		 * Create ArrayCollectionImpl with initial capacity.
		 * @param initialCapacity
		 */
		protected ArrayIteratorImpl() {
			cursor = 0;
		}

		@Override
		public Object[] getArray() {
			return data;
		}

		@Override
		public boolean hasNext() {
			return cursor < size;
		}

		@Override
		public Object next() {
			if (cursor < size) {
				lastRet = cursor;
				return data[cursor++];
			} else {
				throw new NoSuchElementException();
			}
		}

		@Override
		public void remove() {
			if (lastRet < 0 || cursor >= size) {
				throw new IllegalStateException();
			}

			Object[] tmp = new Object[data.length];
			arraycopy(data, 0, tmp, 0, cursor);
			arraycopy(data, cursor + 1, tmp, cursor,
					data.length - cursor - 1);
			size--;
			data = tmp;

		}
	}

	@Override
	public Object[] toArray() {
		return Arrays.copyOf(data, size);
	}

	@Override
	public Object[] toArray(Object[] a) {
		if (a.length < size) {
			return Arrays.copyOf(data, size, a.getClass());
		}
		System.arraycopy(data, 0, a, 0, size);
		if (a.length > size) {
			a[size] = null;
		}
		return a;
	}

	@Override
	public boolean add(Object e) {
		Object[] tmp = new Object[size + 1];
		arraycopy(data, 0, tmp, 0, size);
		tmp[size] = e;
		this.data = tmp;
		size++;
		return true;
	}

	@Override
	public boolean remove(Object o) {
		boolean ifRemove = false;
		if (this.contains(o)) {
			Object[] tmp = Arrays.copyOf(data, data.length - 1);

			if (o == null) {
				for (int index = 0; index < size; index++) {
					if (data[index] == null) {
						arraycopy(data, index + 1, tmp, index,
								tmp.length - index);
						--size;
						data = tmp;
						ifRemove = true;
					}
				}
			} else {
				for (int index = 0; index < size; index++) {
					if (o.equals(data[index])) {
						arraycopy(data, index + 1, tmp, index,
								tmp.length - index);
						--size;
						data = tmp;
						ifRemove = true;
					}
				}
			}
		}
		return ifRemove;
	}

	@Override
	public boolean containsAll(Collection c) {
		for (Object e : c) {
			if (!contains(e)) {
				return false;
			}
		}
		return true;
	}

	@Override
	public boolean addAll(Collection c) {
		if (c == this) {
			throw new IllegalArgumentException();
		}
		Object[] a = c.toArray();
		int numNew = a.length;
		data = Arrays.copyOf(data, size + numNew);
		System.arraycopy(a, 0, data, size, numNew);
		size += numNew;
		return numNew != 0;
	}

	@Override
	public boolean removeAll(Collection c) {
		if (c == null) {
			throw new NullPointerException();
		}
		boolean modified = false;
		for (int i = size - 1; i >= 0; i--) {
			if (c.contains(data[i])) {
				remove(data[i]);
				modified = true;
			}
		}
		return modified;
	}

	@Override
	public boolean retainAll(Collection c) {
		if (c == null) {
			throw new NullPointerException();
		}
		boolean modified = false;
		for (int i = size - 1; i >= 0; i--) {
			if (!c.contains(data[i])) {
				remove(data[i]);
				modified = true;
			}
		}
		return modified;
	}

	@Override
	public void clear() {
		data = new Object[0];
		size = 0;
	}
}